<html>
  <head>
  <title>featureExtractors.py</title>
  </head>
  <body>
  <h3>featureExtractors.py</h3>
  <hr>
  <pre>
<span style="color: red">"Feature extractors for Pacman game states"

</span><span style="color: blue; font-weight: bold">from </span>game <span style="color: blue; font-weight: bold">import </span>Directions<span style="font-weight: bold">, </span>Actions
<span style="color: blue; font-weight: bold">import </span>util

<span style="color: blue; font-weight: bold">class </span>FeatureExtractor<span style="font-weight: bold">:  
  </span><span style="color: blue; font-weight: bold">def </span>getFeatures<span style="font-weight: bold">(</span><span style="color: blue">self</span><span style="font-weight: bold">, </span>state<span style="font-weight: bold">, </span>action<span style="font-weight: bold">):    
    </span><span style="color: darkred">"""
      Returns a dict from features to counts
      Usually, the count will just be 1.0 for
      indicator functions.  
    """
    </span>util<span style="font-weight: bold">.</span>raiseNotDefined<span style="font-weight: bold">()

</span><span style="color: blue; font-weight: bold">class </span>IdentityExtractor<span style="font-weight: bold">(</span>FeatureExtractor<span style="font-weight: bold">):
  </span><span style="color: blue; font-weight: bold">def </span>getFeatures<span style="font-weight: bold">(</span><span style="color: blue">self</span><span style="font-weight: bold">, </span>state<span style="font-weight: bold">, </span>action<span style="font-weight: bold">):
    </span>feats <span style="font-weight: bold">= </span>util<span style="font-weight: bold">.</span>Counter<span style="font-weight: bold">()
    </span>feats<span style="font-weight: bold">[(</span>state<span style="font-weight: bold">,</span>action<span style="font-weight: bold">)] = </span><span style="color: red">1.0
    </span><span style="color: blue; font-weight: bold">return </span>feats

<span style="color: blue; font-weight: bold">def </span>closestFood<span style="font-weight: bold">(</span>pos<span style="font-weight: bold">, </span>food<span style="font-weight: bold">, </span>walls<span style="font-weight: bold">):
  </span><span style="color: darkred">"""
  closestFood -- this is similar to the function that we have
  worked on in the search project; here its all in one place
  """
  </span>fringe <span style="font-weight: bold">= [(</span>pos<span style="font-weight: bold">[</span><span style="color: red">0</span><span style="font-weight: bold">], </span>pos<span style="font-weight: bold">[</span><span style="color: red">1</span><span style="font-weight: bold">], </span><span style="color: red">0</span><span style="font-weight: bold">)]
  </span>expanded <span style="font-weight: bold">= </span>set<span style="font-weight: bold">()
  </span><span style="color: blue; font-weight: bold">while </span>fringe<span style="font-weight: bold">:
    </span>pos_x<span style="font-weight: bold">, </span>pos_y<span style="font-weight: bold">, </span>dist <span style="font-weight: bold">= </span>fringe<span style="font-weight: bold">.</span>pop<span style="font-weight: bold">(</span><span style="color: red">0</span><span style="font-weight: bold">)
    </span><span style="color: blue; font-weight: bold">if </span><span style="font-weight: bold">(</span>pos_x<span style="font-weight: bold">, </span>pos_y<span style="font-weight: bold">) </span><span style="color: blue; font-weight: bold">in </span>expanded<span style="font-weight: bold">:
      </span><span style="color: blue; font-weight: bold">continue
    </span>expanded<span style="font-weight: bold">.</span>add<span style="font-weight: bold">((</span>pos_x<span style="font-weight: bold">, </span>pos_y<span style="font-weight: bold">))
    </span><span style="color: green; font-style: italic"># if we find a food at this location then exit
    </span><span style="color: blue; font-weight: bold">if </span>food<span style="font-weight: bold">[</span>pos_x<span style="font-weight: bold">][</span>pos_y<span style="font-weight: bold">]:
      </span><span style="color: blue; font-weight: bold">return </span>dist
    <span style="color: green; font-style: italic"># otherwise spread out from the location to its neighbours
    </span>nbrs <span style="font-weight: bold">= </span>Actions<span style="font-weight: bold">.</span>getLegalNeighbors<span style="font-weight: bold">((</span>pos_x<span style="font-weight: bold">, </span>pos_y<span style="font-weight: bold">), </span>walls<span style="font-weight: bold">)
    </span><span style="color: blue; font-weight: bold">for </span>nbr_x<span style="font-weight: bold">, </span>nbr_y <span style="color: blue; font-weight: bold">in </span>nbrs<span style="font-weight: bold">:
      </span>fringe<span style="font-weight: bold">.</span>append<span style="font-weight: bold">((</span>nbr_x<span style="font-weight: bold">, </span>nbr_y<span style="font-weight: bold">, </span>dist<span style="font-weight: bold">+</span><span style="color: red">1</span><span style="font-weight: bold">))
  </span><span style="color: green; font-style: italic"># no food found
  </span><span style="color: blue; font-weight: bold">return </span><span style="color: blue">None

</span><span style="color: blue; font-weight: bold">class </span>SimpleExtractor<span style="font-weight: bold">(</span>FeatureExtractor<span style="font-weight: bold">):
  </span><span style="color: darkred">"""
  Returns simple features for a basic reflex Pacman:
  - whether food will be eaten
  - how far away the next food is
  - whether a ghost collision is imminent
  - whether a ghost is one step away
  """
  
  </span><span style="color: blue; font-weight: bold">def </span>getFeatures<span style="font-weight: bold">(</span><span style="color: blue">self</span><span style="font-weight: bold">, </span>state<span style="font-weight: bold">, </span>action<span style="font-weight: bold">):
    </span><span style="color: green; font-style: italic"># extract the grid of food and wall locations and get the ghost locations
    </span>food <span style="font-weight: bold">= </span>state<span style="font-weight: bold">.</span>getFood<span style="font-weight: bold">()
    </span>walls <span style="font-weight: bold">= </span>state<span style="font-weight: bold">.</span>getWalls<span style="font-weight: bold">()
    </span>ghosts <span style="font-weight: bold">= </span>state<span style="font-weight: bold">.</span>getGhostPositions<span style="font-weight: bold">()

    </span>features <span style="font-weight: bold">= </span>util<span style="font-weight: bold">.</span>Counter<span style="font-weight: bold">()
    
    </span>features<span style="font-weight: bold">[</span><span style="color: red">"bias"</span><span style="font-weight: bold">] = </span><span style="color: red">1.0
    
    </span><span style="color: green; font-style: italic"># compute the location of pacman after he takes the action
    </span>x<span style="font-weight: bold">, </span>y <span style="font-weight: bold">= </span>state<span style="font-weight: bold">.</span>getPacmanPosition<span style="font-weight: bold">()
    </span>dx<span style="font-weight: bold">, </span>dy <span style="font-weight: bold">= </span>Actions<span style="font-weight: bold">.</span>directionToVector<span style="font-weight: bold">(</span>action<span style="font-weight: bold">)
    </span>next_x<span style="font-weight: bold">, </span>next_y <span style="font-weight: bold">= </span>int<span style="font-weight: bold">(</span>x <span style="font-weight: bold">+ </span>dx<span style="font-weight: bold">), </span>int<span style="font-weight: bold">(</span>y <span style="font-weight: bold">+ </span>dy<span style="font-weight: bold">)
    
    </span><span style="color: green; font-style: italic"># count the number of ghosts 1-step away
    </span>features<span style="font-weight: bold">[</span><span style="color: red">"#-of-ghosts-1-step-away"</span><span style="font-weight: bold">] = </span>sum<span style="font-weight: bold">((</span>next_x<span style="font-weight: bold">, </span>next_y<span style="font-weight: bold">) </span><span style="color: blue; font-weight: bold">in </span>Actions<span style="font-weight: bold">.</span>getLegalNeighbors<span style="font-weight: bold">(</span>g<span style="font-weight: bold">, </span>walls<span style="font-weight: bold">) </span><span style="color: blue; font-weight: bold">for </span>g <span style="color: blue; font-weight: bold">in </span>ghosts<span style="font-weight: bold">)

    </span><span style="color: green; font-style: italic"># if there is no danger of ghosts then add the food feature
    </span><span style="color: blue; font-weight: bold">if not </span>features<span style="font-weight: bold">[</span><span style="color: red">"#-of-ghosts-1-step-away"</span><span style="font-weight: bold">] </span><span style="color: blue; font-weight: bold">and </span>food<span style="font-weight: bold">[</span>next_x<span style="font-weight: bold">][</span>next_y<span style="font-weight: bold">]:
      </span>features<span style="font-weight: bold">[</span><span style="color: red">"eats-food"</span><span style="font-weight: bold">] = </span><span style="color: red">1.0
    
    </span>dist <span style="font-weight: bold">= </span>closestFood<span style="font-weight: bold">((</span>next_x<span style="font-weight: bold">, </span>next_y<span style="font-weight: bold">), </span>food<span style="font-weight: bold">, </span>walls<span style="font-weight: bold">)
    </span><span style="color: blue; font-weight: bold">if </span>dist <span style="color: blue; font-weight: bold">is not </span><span style="color: blue">None</span><span style="font-weight: bold">:
      </span><span style="color: green; font-style: italic"># make the distance a number less than one otherwise the update
      # will diverge wildly
      </span>features<span style="font-weight: bold">[</span><span style="color: red">"closest-food"</span><span style="font-weight: bold">] = </span>float<span style="font-weight: bold">(</span>dist<span style="font-weight: bold">) / (</span>walls<span style="font-weight: bold">.</span>width <span style="font-weight: bold">* </span>walls<span style="font-weight: bold">.</span>height<span style="font-weight: bold">) 
    </span>features<span style="font-weight: bold">.</span>divideAll<span style="font-weight: bold">(</span><span style="color: red">10.0</span><span style="font-weight: bold">)
    </span><span style="color: blue; font-weight: bold">return </span>features
  </pre>
  </body>
  </html>
  